home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ImageMagick / xtp / xtp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  43.3 KB  |  1,420 lines

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. %                                                                             %
  4. %                                                                             %
  5. %                                                                             %
  6. %                            X   X  TTTTT PPPP                                %
  7. %                             X X     T   P   P                               %
  8. %                              X      T   PPPP                                %
  9. %                             X X     T   P                                   %
  10. %                            X   X    T   P                                   %
  11. %                                                                             %
  12. %                                                                             %
  13. %                         File transfer program.                              %
  14. %                                                                             %
  15. %                                                                             %
  16. %                                                                             %
  17. %                           Software Design                                   %
  18. %                             John Cristy                                     %
  19. %                             October 1992                                    %
  20. %                                                                             %
  21. %                                                                             %
  22. %  Copyright 1993 E. I. Dupont de Nemours & Company                           %
  23. %                                                                             %
  24. %  Permission to use, copy, modify, distribute, and sell this software and    %
  25. %  its documentation for any purpose is hereby granted without fee,           %
  26. %  provided that the above copyright notice appear in all copies and that     %
  27. %  both that copyright notice and this permission notice appear in            %
  28. %  supporting documentation, and that the name of E. I. Dupont de Nemours     %
  29. %  & Company not be used in advertising or publicity pertaining to            %
  30. %  distribution of the software without specific, written prior               %
  31. %  permission.  E. I. Dupont de Nemours & Company makes no representations    %
  32. %  about the suitability of this software for any purpose.  It is provided    %
  33. %  "as is" without express or implied warranty.                               %
  34. %                                                                             %
  35. %  E. I. Dupont de Nemours & Company disclaims all warranties with regard     %
  36. %  to this software, including all implied warranties of merchantability      %
  37. %  and fitness, in no event shall E. I. Dupont de Nemours & Company be        %
  38. %  liable for any special, indirect or consequential damages or any           %
  39. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  40. %  in an action of contract, negligence or other tortious action, arising     %
  41. %  out of or in connection with the use or performance of this software.      %
  42. %                                                                             %
  43. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  44. %
  45. %  Xtp is a utility for retrieving, listing, or printing files from a
  46. %  remote network site.  Xtp performs most of the same functions as the
  47. %  FTP program, but does not require any interactive commands.  You simply
  48. %  specify the file transfer task on the command line and xtp performs the
  49. %  transfer automatically.
  50. %
  51. %  This program was adapted from a similiar program written by Steve Singles,
  52. %  University of Delaware.
  53. %
  54. %  Command syntax:
  55. %
  56. %  Usage: xtp [-options ...] <host/ip address> [ <home directory> ]
  57. %
  58. %  Where options include:
  59. %    -account password      supplemental password
  60. %    -binary                retrieve files as binary
  61. %    -exclude expression    exclude files that match the expression
  62. %    -directory expression  list file names that match the expression
  63. %    -ident password        specifies password
  64. %    -port number           port number of FTP server
  65. %    -print expression      print files that match the expression
  66. %    -prune                 do not recursively search for files
  67. %    -retrieve expression   retrieve files that match the expression
  68. %    -send expression       send files that match the expression
  69. %    -timeout seconds       specifies maximum seconds of XTP session
  70. %    -user name             identify yourself to the remote FTP server
  71. %
  72. %
  73. */
  74.  
  75. /*
  76.   Include declarations.
  77. */
  78. #define _POSIX_SOURCE  1
  79. #include "xtp.h"
  80. #include "regular.h"
  81. #include <unistd.h>
  82. #include <sys/types.h>
  83. #include <signal.h>
  84. #include <termios.h>
  85. #include <fcntl.h>
  86. #include <sys/stat.h>
  87. #include <sys/wait.h>
  88. /*
  89.   Variable declarations.
  90. */
  91. static char
  92.   *client_name,
  93.   slave_tty[16];
  94.  
  95. static int
  96.   master,
  97.   status;
  98.  
  99. static RegularExpression
  100.   *directory_expression,
  101.   *exclude_expression,
  102.   *print_expression,
  103.   *retrieve_expression;
  104.  
  105. /*
  106.   External declarations.
  107. */
  108. extern char
  109.   *GetHostInfo _Declare((char *));
  110.  
  111. /*
  112.   Forward declarations.
  113. */
  114. static char
  115.   *Wait _Declare((void));
  116.  
  117. static void
  118.   DirectoryRequest _Declare((char *, char *)),
  119.   PrintRequest _Declare((char *,unsigned int)),
  120.   RetrieveRequest _Declare((char *,unsigned int));
  121.  
  122. /*
  123. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  124. %                                                                             %
  125. %                                                                             %
  126. %                                                                             %
  127. %   D i r e c t o r y R e q u e s t                                           %
  128. %                                                                             %
  129. %                                                                             %
  130. %                                                                             %
  131. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  132. %
  133. %  Function DirectoryRequest lists a file name and its attributes.
  134. %
  135. %  The format of the DirectoryRequest routine is:
  136. %
  137. %    DirectoryRequest(fileinfo,filename)
  138. %
  139. %  A description of each parameter follows:
  140. %
  141. %    o filename:  Specifies a pointer to a character array that contains
  142. %      information about the file.
  143. %
  144. %    o filename:  Specifies a pointer to a character array that contains
  145. %      the name of the file.
  146. %
  147. */
  148. static void DirectoryRequest(fileinfo,filename)
  149. char
  150.   *fileinfo,
  151.   *filename;
  152. {
  153.   status=0;
  154.   if (*fileinfo == '\0')
  155.     (void) fprintf(stdout,"%s\n",filename);
  156.   else
  157.     (void) fprintf(stdout,"%s %s\n",fileinfo,filename);
  158. }
  159.  
  160. /*
  161. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  162. %                                                                             %
  163. %                                                                             %
  164. %                                                                             %
  165. %   E r r o r                                                                 %
  166. %                                                                             %
  167. %                                                                             %
  168. %                                                                             %
  169. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  170. %
  171. %  Function Error displays an error message and then terminates the program.
  172. %
  173. %  The format of the Error routine is:
  174. %
  175. %      Error(message,qualifier)
  176. %
  177. %  A description of each parameter follows:
  178. %
  179. %    o message: Specifies the message to display before terminating the
  180. %      program.
  181. %
  182. %    o qualifier: Specifies any qualifier to the message.
  183. %
  184. %
  185. */
  186. void Error(message,qualifier)
  187. char
  188.   *message,
  189.   *qualifier;
  190. {
  191.   (void) fprintf(stderr,"%s: %s",client_name,message);
  192.   if (qualifier != (char *) NULL)
  193.     (void) fprintf(stderr," (%s)",qualifier);
  194.   (void) fprintf(stderr,".\n");
  195.   exit(1);
  196. }
  197.  
  198. /*
  199. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  200. %                                                                             %
  201. %                                                                             %
  202. %                                                                             %
  203. %   E x e c u t e F t p                                                       %
  204. %                                                                             %
  205. %                                                                             %
  206. %                                                                             %
  207. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  208. %
  209. %  Function ExecuteFtp executes the FTP program as a child process.
  210. %
  211. %  The format of the ExecuteFtp routine is:
  212. %
  213. %    ExecuteFtp(hostname,port)
  214. %
  215. %  A description of each parameter follows:
  216. %
  217. %    o hostname:  Specifies a pointer to a character array that contains the
  218. %      name of the host to establish a connection to a FTP server.
  219. %
  220. %    o port:  Specifies a port number.  If the port number is NULL, xtp
  221. %      attempts to contact a FTP server at the default port.
  222. %
  223. %
  224. %
  225. */
  226. static void ExecuteFtp(hostname,port)
  227. char
  228.   *hostname,
  229.   *port;
  230. {
  231.   int
  232.     slave;
  233.  
  234.   struct sigaction
  235.     action;
  236.  
  237.   struct termios
  238.     attributes;
  239.  
  240.   /*
  241.     Get slave tty line.
  242.   */
  243.   action.sa_handler=SIG_IGN;
  244.   (void) sigemptyset(&action.sa_mask);
  245.   action.sa_flags=0;
  246.   (void) sigaction(SIGTSTP,&action,(struct sigaction *) NULL);
  247.   if (isatty(STDIN_FILENO))
  248.     (void) setsid();
  249.   slave=open(slave_tty,O_RDWR | O_NOCTTY);
  250.   if (slave < 0)
  251.     Error("Unable to open slave pseudo-terminal",slave_tty);
  252.   /*
  253.     Condition slave tty line.
  254.   */
  255.   (void) tcgetattr(slave,&attributes);
  256.   attributes.c_iflag&=(~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | INLCR |
  257.     IGNCR | ICRNL | IXON));
  258.   attributes.c_iflag|=IGNBRK | IXOFF;
  259.   attributes.c_oflag&=(~OPOST);
  260.   attributes.c_lflag&=
  261.     (~(ECHO | ECHOE | ECHOK | ECHONL | ICANON | ISIG | NOFLSH | TOSTOP));
  262.   attributes.c_cflag&=(~(CSIZE | CSTOPB | HUPCL | PARENB));
  263.   attributes.c_cflag|=CLOCAL | CREAD | CS8;
  264.   (void) tcflush(slave,TCIFLUSH);
  265.   (void) tcsetattr(slave,TCSANOW,&attributes);
  266.   /*
  267.     Execute FTP program as a child process.
  268.   */
  269.   (void) close(master);
  270.   (void) dup2(slave,STDIN_FILENO);
  271.   (void) dup2(slave,STDOUT_FILENO);
  272.   (void) dup2(slave,STDERR_FILENO);
  273.   (void) close(slave);
  274.   (void) execlp("ftp","ftp","-n","-i","-g","-v",hostname,port,(char *) 0);
  275.   perror("ftp");
  276.   (void) kill(0,SIGTERM);
  277. }
  278.  
  279. /*
  280. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  281. %                                                                             %
  282. %                                                                             %
  283. %                                                                             %
  284. %   G e t P a s s w o r d                                                     %
  285. %                                                                             %
  286. %                                                                             %
  287. %                                                                             %
  288. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  289. %
  290. %  Function GetPassword prompts the user for a password.  The password is
  291. %  not echoed on the terminal.
  292. %
  293. %  The format of the GetPassword routine is:
  294. %
  295. %    password=GetPassword(prompt)
  296. %
  297. %  A description of each parameter follows:
  298. %
  299. %    o password:  Specifies a pointer to a character array that contains
  300. %      accepted from the user.
  301. %
  302. %    o prompt:  Specifies a pointer to a character array that contains
  303. %      a message to display to the user.
  304. %
  305. %
  306. */
  307. static char *GetPassword(prompt)
  308. char
  309.   *prompt;
  310. {
  311.   static char
  312.     password[2048];
  313.  
  314.   struct termios
  315.     attributes;
  316.  
  317.   (void) fprintf(stdout,"%s",prompt);
  318.   (void) fflush(stdout);
  319.   (void) tcgetattr(STDIN_FILENO,&attributes);
  320.   attributes.c_lflag&=(~ECHO);
  321.   (void) tcsetattr(STDIN_FILENO,TCSANOW,&attributes);
  322.   (void) gets(password);
  323.   attributes.c_lflag|=ECHO;
  324.   (void) tcsetattr(STDIN_FILENO,TCSANOW,&attributes);
  325.   (void) fprintf(stdout,"\n");
  326.   return(password);
  327. }
  328.  
  329. /*
  330. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  331. %                                                                             %
  332. %                                                                             %
  333. %                                                                             %
  334. %   G e t P s e u d o T e r m i n a l                                         %
  335. %                                                                             %
  336. %                                                                             %
  337. %                                                                             %
  338. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  339. %
  340. %  Function GetPseudoTerminal returns a master/slave pair of pseudo-terminals.
  341. %
  342. %  The format of the GetPseudoTerminal routine is:
  343. %
  344. %    GetPseudoTerminal()
  345. %
  346. %
  347. */
  348. static void GetPseudoTerminal()
  349. {
  350.   char
  351.     master_tty[16];
  352.  
  353.   register char
  354.     *bank,
  355.     *cp;
  356.  
  357.   struct stat
  358.     info;
  359.  
  360.   for (bank="pqrs"; *bank; bank++)
  361.   {
  362.     (void) sprintf(master_tty,"/dev/pty%c0",*bank);
  363.     if (stat(master_tty,&info) < 0)
  364.       break;
  365.     for (cp="0123456789abcdef"; *cp; cp++)
  366.     {
  367.       (void) sprintf((char *) master_tty,"/dev/pty%c%c",*bank,*cp);
  368.       master=open(master_tty,O_RDWR);
  369.       if (master >= 0)
  370.         {
  371.           /*
  372.             Verify slave side is usable.
  373.           */
  374.           (void) sprintf(slave_tty,"/dev/tty%c%c",*bank,*cp);
  375.           if (access(slave_tty,R_OK | W_OK) == 0)
  376.             {
  377.               struct termios
  378.                 attributes;
  379.  
  380.               /*
  381.                 Condition master tty line.
  382.               */
  383.               (void) tcgetattr(master,&attributes);
  384.               attributes.c_lflag&=(~(ICANON | ECHO));
  385.               (void) tcflush(master,TCIFLUSH);
  386.               (void) tcsetattr(master,TCSANOW,&attributes);
  387.               return;
  388.             }
  389.           (void) close(master);
  390.         }
  391.     }
  392.   }
  393.   Error("All network ports in use",(char *) NULL);
  394. }
  395.  
  396. /*
  397. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  398. %                                                                             %
  399. %                                                                             %
  400. %                                                                             %
  401. %   M a k e D i r e c t o r y                                                 %
  402. %                                                                             %
  403. %                                                                             %
  404. %                                                                             %
  405. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  406. %
  407. %  Function MakeDirectory checks each component of a directory path and if it
  408. %  does not exist, creates it.
  409. %
  410. %  The format of the MakeDirectory routine is:
  411. %
  412. %    MakeDirectory(directory)
  413. %
  414. %  A description of each parameter follows:
  415. %
  416. %    o directory:  Specifies a pointer to a character array that contains
  417. %      the name of the directory to create.
  418. %
  419. %
  420. */
  421. static int MakeDirectory(directory)
  422. char
  423.   *directory;
  424. {
  425.   register char
  426.     *p;
  427.  
  428.   struct stat
  429.     info;
  430.  
  431.   /*
  432.     Determine first component of the directory.
  433.   */
  434.   p=strrchr(directory,'/');
  435.   if ((p == (char *) NULL) || (p == directory))
  436.     return(False);
  437.   *p='\0';
  438.   if (lstat(directory,&info) < 0)
  439.     {
  440.       /*
  441.         Path component does not exist;  create it.
  442.       */
  443.       if (MakeDirectory(directory) == 0)
  444.         if (mkdir(directory,(mode_t) 0777) >= 0)
  445.           {
  446.             *p='/';
  447.             return(False);
  448.           }
  449.     }
  450.   else
  451.     if (S_ISDIR(info.st_mode))
  452.       {
  453.         /*
  454.           Path component already exists.
  455.         */
  456.         *p='/';
  457.         return(False);
  458.       }
  459.   /*
  460.     Path component is a file not a directory.
  461.   */
  462.   *p='/';
  463.   return(True);
  464. }
  465.  
  466. /*
  467. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  468. %                                                                             %
  469. %                                                                             %
  470. %                                                                             %
  471. %   P r i n t R e q u e s t                                                   %
  472. %                                                                             %
  473. %                                                                             %
  474. %                                                                             %
  475. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  476. %
  477. %  Function PrintRequest prints a file on the remote FTP server.
  478. %
  479. %  The format of the PrintRequest routine is:
  480. %
  481. %    PrintRequest(filename,verbose)
  482. %
  483. %  A description of each parameter follows:
  484. %
  485. %    o filename:  Specifies a pointer to a character array that contains
  486. %      the name of the file to print.
  487. %
  488. %    o verbose: An unsigned integer.  A value other than zero dhows all
  489. %      responses from the remote server.
  490. %
  491. %
  492. */
  493. static void PrintRequest(filename,verbose)
  494. char
  495.   *filename;
  496.  
  497. unsigned int
  498.   verbose;
  499. {
  500.   char
  501.     command[2048],
  502.     *response;
  503.  
  504.   /*
  505.     get remote-file [ - | < |zcat > ].
  506.   */
  507.   (void) sprintf(command,"get %s",filename);
  508.   if (strcmp(filename+strlen(filename)-2,".Z") == 0)
  509.     (void) strcat(command," |zcat\n");
  510.   else
  511.     (void) strcat(command," -\n");
  512.   (void) write(master,command,strlen(command));
  513.   (void) fprintf(stdout,"%s:\n",filename);
  514.   while ((response=Wait()))
  515.     if (status == 0)
  516.       (void) fprintf(stdout,"%s\n",response);
  517.     else
  518.       if ((status == 5) || verbose)
  519.         (void) fprintf(stderr,"%s\n",response);
  520. }
  521.  
  522. /*
  523. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  524. %                                                                             %
  525. %                                                                             %
  526. %                                                                             %
  527. %   P r o c e s s R e q u e s t                                               %
  528. %                                                                             %
  529. %                                                                             %
  530. %                                                                             %
  531. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  532. %
  533. %  Function ProcessRequest first records any file in the current directory
  534. %  of the remote FTP server or any of its subdirectories.  Next each filename
  535. %  is either accepted or rejected based on a user specified regular
  536. %  expresssion.  If any files match the regular expression, its filename is
  537. %  listed, it is printed, or it is retrieved as specified on the command line.
  538. %
  539. %  The format of the ProcessRequest routine is:
  540. %
  541. %    ProcessRequest(prune,verbose)
  542. %
  543. %  A description of each parameter follows:
  544. %
  545. %    o prune:  Specifies whether to recusively search for files.
  546. %
  547. %    o verbose: An unsigned integer.  A value other than zero dhows all
  548. %      responses from the remote server.
  549. %
  550. %
  551. */
  552. static void ProcessRequest(prune,verbose)
  553. unsigned int
  554.   prune,
  555.   verbose;
  556. {
  557.   typedef struct _DirectoryNode
  558.   {
  559.     char
  560.       *info,
  561.       *name;
  562.  
  563.     struct _DirectoryNode
  564.       *next;
  565.   } DirectoryNode;
  566.  
  567.   char
  568.     command[2048],
  569.     directory[2048],
  570.     *info,
  571.     *name,
  572.     *response;
  573.  
  574.   DirectoryNode
  575.     *next,
  576.     *root;
  577.  
  578.   register char
  579.     *p;
  580.  
  581.   register DirectoryNode
  582.     **last,
  583.     *node;
  584.  
  585.   RegularExpression
  586.     *date_expression,
  587.     *mode_expression;
  588.  
  589.   unsigned int
  590.     unix_filesystem;
  591.  
  592.   /*
  593.     Initialize function variables.
  594.   */
  595.   root=(DirectoryNode *) NULL;
  596.   last=(&root);
  597.   *directory='\0';
  598.   response=(char *) NULL;
  599.   unix_filesystem=False;
  600.   if (!prune)
  601.     {
  602.       /*
  603.         Obtain a time sorted recursive directory if available.
  604.       */
  605.       (void) strcpy(command,"get ls-ltR.Z |zcat\n");
  606.       (void) write(master,command,strlen(command));
  607.       while ((response=Wait()))
  608.         if ((status == 0) || (status == 5))
  609.           break;
  610.       if (status == 5)
  611.         {
  612.           /*
  613.             Obtain a recursive directory if available.
  614.           */
  615.           while (Wait());
  616.           (void) strcpy(command,"get ls-lR.Z |zcat\n");
  617.           (void) write(master,command,strlen(command));
  618.           while ((response=Wait()))
  619.             if ((status == 0) || (status == 5))
  620.               break;
  621.         }
  622.       if (status == 5)
  623.         while (Wait());
  624.       else
  625.         {
  626.           (void) fprintf(stderr,"Using existing directory listing...\n");
  627.           unix_filesystem=True;
  628.         }
  629.     }
  630.   if (prune || !unix_filesystem)
  631.     {
  632.       /*
  633.         Determine if the FTP server has unix-style filenames.
  634.       */
  635.       mode_expression=CompileRegularExpression("^.[rwx-][rwx-][rwx-]");
  636.       (void) strcpy(command,"dir\n");
  637.       (void) write(master,command,strlen(command));
  638.       while ((response=Wait()))
  639.         if (!unix_filesystem)
  640.           if (*response != '\0')
  641.             unix_filesystem=ExecuteRegularExpression(mode_expression,response);
  642.       (void) free((char *) mode_expression);
  643.       /*
  644.         Obtain recursive directory listing with the FTP directory command.
  645.       */
  646.       if (prune)
  647.         (void) strcpy(command,"dir\n");
  648.       else
  649.         if (unix_filesystem)
  650.           (void) strcpy(command,"ls -ltR\n");
  651.         else
  652.           (void) strcpy(command,"ls [...]\n");
  653.       (void) write(master,command,strlen(command));
  654.       while ((response=Wait()))
  655.         if ((status == 0) || (status == 5))
  656.           break;
  657.       if (status == 5)
  658.         {
  659.           /*
  660.             Directory command has limited functionality.
  661.           */
  662.           while (Wait());
  663.           (void) strcpy(command,"dir\n");
  664.           (void) write(master,command,strlen(command));
  665.           while ((response=Wait()))
  666.             if (status == 0)
  667.               break;
  668.         }
  669.     }
  670.   status=(-1);
  671.   if (response == (char *) NULL)
  672.     return;
  673.   if (!unix_filesystem)
  674.     do
  675.     {
  676.       /*
  677.         Link non unix-style file into file list.
  678.       */
  679.       if ((status > 0) || (*response == '\0'))
  680.         continue;
  681.       while (*response == ' ')
  682.         response++;
  683.       /*
  684.         Extract file name & info.
  685.       */
  686.       name=response;
  687.       info=response;
  688.       while ((*info != ' ') && *info)
  689.         info++;
  690.       *info='\0';
  691.       node=(DirectoryNode *) malloc(sizeof(DirectoryNode));
  692.       if (node == (DirectoryNode *) NULL)
  693.         Error("Unable to allocate memory",(char *) NULL);
  694.       node->name=(char *) malloc((strlen(name)+1)*sizeof(char));
  695.       node->info=(char *) malloc((strlen(info)+1)*sizeof(char));
  696.       if ((node->name == (char *) NULL) || (node->info == (char *) NULL))
  697.         Error("Unable to allocate memory",(char *) NULL);
  698.       (void) strcpy(node->name,name);
  699.       (void) strcpy(node->info,info);
  700.       node->next=(DirectoryNode *) NULL;
  701.       if (exclude_expression)
  702.         if (ExecuteRegularExpression(exclude_expression,node->name))
  703.           {
  704.             /*
  705.               Free allocated memory for this node.
  706.             */
  707.             (void) free((char *) node->info);
  708.             (void) free((char *) node->name);
  709.             (void) free((char *) node);
  710.             continue;
  711.           }
  712.       *last=node;
  713.       last=(&node->next);
  714.     }
  715.     while ((response=Wait()));
  716.   else
  717.     {
  718.       RegularExpression
  719.         *access_expression;
  720.  
  721.       access_expression=
  722.         CompileRegularExpression("Permission denied|not found|cannot access");
  723.       date_expression=
  724.         CompileRegularExpression(" [0-9][0-9][0-9][0-9]|[0-9][0-9]:[0-9][0-9]");
  725.       do
  726.       {
  727.         /*
  728.            Link unix-style file into file list.
  729.         */
  730.         if ((status > 0) || (*response == '\0'))
  731.           continue;
  732.         while (*response == ' ')
  733.           response++;
  734.         p=response+strlen(response)-1;
  735.         if ((*response == '-') || (*response == 'F'))
  736.           {
  737.             if (ExecuteRegularExpression(access_expression,response))
  738.               continue;
  739.             /*
  740.               Extract file info & name.
  741.             */
  742.             while (p-- > (response+5))
  743.               if (*p == ' ')
  744.                 if (!ExecuteRegularExpression(date_expression,p-5))
  745.                   *p='_';
  746.                 else
  747.                   break;
  748.             *p++='\0';
  749.             while (*p == ' ')
  750.               p++;
  751.             name=p;
  752.             info=response;
  753.             node=(DirectoryNode *) malloc(sizeof(DirectoryNode));
  754.             if (node == (DirectoryNode *) NULL)
  755.               Error("Unable to allocate memory",(char *) NULL);
  756.             node->name=(char *) malloc(strlen(directory)+strlen(name)+1);
  757.             node->info=(char *) malloc(strlen(info)+1);
  758.             if ((node->name == (char *) NULL) || (node->info == (char *) NULL))
  759.               Error("Unable to allocate memory",(char *) NULL);
  760.             (void) strcpy(node->name,directory);
  761.             (void) strcat(node->name,name);
  762.             (void) strcpy(node->info,info);
  763.             node->next=(DirectoryNode *) NULL;
  764.             if (exclude_expression)
  765.               if (ExecuteRegularExpression(exclude_expression,node->name))
  766.                 {
  767.                   /*
  768.                     Free allocated memory for this node.
  769.                   */
  770.                   (void) free((char *) node->info);
  771.                   (void) free((char *) node->name);
  772.                   (void) free((char *) node);
  773.                   continue;
  774.                 }
  775.             *last=node;
  776.             last=(&node->next);
  777.           }
  778.         else
  779.           if (*p == ':')
  780.             {
  781.               /*
  782.                 File is a directory.
  783.               */
  784.               do { p--; } while (*p == ' ');
  785.               *(++p)='\0';
  786.               (void) strcpy(directory,response);
  787.               (void) strcat(directory,"/");
  788.             }
  789.       }
  790.       while ((response=Wait()));
  791.       (void) free((char *) access_expression);
  792.       (void) free((char *) date_expression);
  793.     }
  794.   /*
  795.     Traverse the file list and act on a filename if it matches the regular
  796.     expression.
  797.   */
  798.   status=(-1);
  799.   node=root;
  800.   while (node)
  801.   {
  802.     if (directory_expression)
  803.       if (ExecuteRegularExpression(directory_expression,node->name))
  804.         (void) DirectoryRequest(node->info,node->name);
  805.     if (print_expression)
  806.       if (ExecuteRegularExpression(print_expression,node->name))
  807.         (void) PrintRequest(node->name,verbose);
  808.     if (retrieve_expression)
  809.       if (ExecuteRegularExpression(retrieve_expression,node->name))
  810.         (void) RetrieveRequest(node->name,verbose);
  811.     /*
  812.       Free allocated memory for this node.
  813.     */
  814.     (void) free((char *) node->info);
  815.     (void) free((char *) node->name);
  816.     next=node->next;
  817.     (void) free((char *) node);
  818.     node=next;
  819.   }
  820.   if (status < 0)
  821.     Warning("no files matched your expression",(char *) NULL);
  822. }
  823.  
  824. /*
  825. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  826. %                                                                             %
  827. %                                                                             %
  828. %                                                                             %
  829. %   R e t r i e v e R e q u e s t                                             %
  830. %                                                                             %
  831. %                                                                             %
  832. %                                                                             %
  833. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  834. %
  835. %  Function RetrieveRequest retrieves a file from the remote FTP server.
  836. %
  837. %  The format of the RetrieveRequest routine is:
  838. %
  839. %    RetrieveRequest(filename,verbose)
  840. %
  841. %  A description of each parameter follows:
  842. %
  843. %    o filename:  Specifies a pointer to a character array that contains
  844. %      the name of the file to retrieve.
  845. %
  846. %    o verbose: An unsigned integer.  A value other than zero dhows all
  847. %      responses from the remote server.
  848. %
  849. %
  850. */
  851. static void RetrieveRequest(filename,verbose)
  852. char
  853.   *filename;
  854.  
  855. unsigned int
  856.   verbose;
  857. {
  858.   char
  859.     command[2048],
  860.     *response;
  861.  
  862.   /*
  863.     get remote-file
  864.   */
  865.   (void) MakeDirectory(filename);
  866.   (void) sprintf(command,"get %s\n",filename);
  867.   (void) write(master,command,strlen(command));
  868.   while ((response=Wait()))
  869.     if (status == 0)
  870.       (void) fprintf(stdout,"%s\n",response);
  871.     else
  872.       if ((status == 5) || verbose)
  873.         (void) fprintf(stderr,"%s\n",response);
  874. }
  875.  
  876. /*
  877. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  878. %                                                                             %
  879. %                                                                             %
  880. %                                                                             %
  881. %   S i g n a l A l a r m                                                     %
  882. %                                                                             %
  883. %                                                                             %
  884. %                                                                             %
  885. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  886. %
  887. %  Function SignalAlarm is called if the timer expires.
  888. %
  889. %  The format of the SignalAlarm routine is:
  890. %
  891. %    SignalAlarm()
  892. %
  893. %
  894. */
  895. static void SignalAlarm()
  896. {
  897.   char
  898.     message[2048];
  899.  
  900.   int
  901.     process_status;
  902.  
  903.   while (waitpid((pid_t) NULL,&process_status,WNOHANG) > 0);
  904.   (void) sprintf(message,"timeout expired, status %x",process_status);
  905.   Error(message,(char *) NULL);
  906. }
  907.  
  908.  
  909. /*
  910. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  911. %                                                                             %
  912. %                                                                             %
  913. %                                                                             %
  914. %   S i g n a l C h i l d                                                     %
  915. %                                                                             %
  916. %                                                                             %
  917. %                                                                             %
  918. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  919. %
  920. %  Function SignalChild is called if the status of the child process changes.
  921. %
  922. %  The format of the SignalChild routine is:
  923. %
  924. %    SignalChild()
  925. %
  926. %
  927. */
  928. static void SignalChild()
  929. {
  930.   char
  931.     message[2048];
  932.  
  933.   int
  934.     process_status;
  935.  
  936.   while (waitpid((pid_t) NULL,&process_status,WNOHANG) > 0);
  937.   (void) sprintf(message,"child died, status %x",process_status);
  938.   Error(message,(char *) NULL);
  939. }
  940.  
  941. /*
  942. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  943. %                                                                             %
  944. %                                                                             %
  945. %                                                                             %
  946. %   U s a g e                                                                 %
  947. %                                                                             %
  948. %                                                                             %
  949. %                                                                             %
  950. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  951. %
  952. %  Procedure Usage displays the program usage;
  953. %
  954. %  The format of the Usage routine is:
  955. %
  956. %      Usage()
  957. %
  958. %
  959. */
  960. static void Usage()
  961. {
  962.   char
  963.     **p;
  964.  
  965.   static char
  966.     *options[]=
  967.     {
  968.       "-account password      supplemental password",
  969.       "-binary                retrieve files as binary",
  970.       "-exclude expression    exclude files that match the expression",
  971.       "-directory expression  list file names that match the expression",
  972.       "-ident password        specifies password",
  973.       "-port number           port number of FTP server",
  974.       "-print expression      print files that match the expression",
  975.       "-prune                 do not recursively search for files",
  976.       "-retrieve expression   retrieve files that match the expression",
  977.       "-send expression       send files that match the expression",
  978.       "-timeout seconds       specifies maximum seconds of XTP session",
  979.       "-user name             identify yourself to the remote FTP server",
  980.       "-verbose               show all responses from the remote server",
  981.       NULL
  982.     };
  983.   (void) fprintf(stderr,
  984.     "Usage: %s [-options ...] <host/ip address> [ <home directory> ]\n",
  985.     client_name);
  986.   (void) fprintf(stderr,"\nWhere options include:\n");
  987.   for (p=options; *p; p++)
  988.     (void) fprintf(stderr,"  %s\n",*p);
  989.   exit(1);
  990. }
  991.  
  992. /*
  993. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  994. %                                                                             %
  995. %                                                                             %
  996. %                                                                             %
  997. %   W a i t                                                                   %
  998. %                                                                             %
  999. %                                                                             %
  1000. %                                                                             %
  1001. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1002. %
  1003. %  Function Wait reads a line of output from the remote FTP server.
  1004. %
  1005. %  The format of the Wait() routine is:
  1006. %
  1007. %    response=Wait()
  1008. %
  1009. %  A description of each parameter follows:
  1010. %
  1011. %    o response:  Function Wait returns this pointer to the output obtained
  1012. %      from the remote FTP server.
  1013. %
  1014. %
  1015. */
  1016. static char *Wait()
  1017. {
  1018.   register char
  1019.     *p;
  1020.  
  1021.   static char
  1022.     buffer[1024],
  1023.     *q;
  1024.  
  1025.   static char
  1026.     line[1024];
  1027.  
  1028.   static int
  1029.     count=0;
  1030.  
  1031.   status=0;
  1032.   p=line;
  1033.   do
  1034.   {
  1035.     if (count <= 0)
  1036.       {
  1037.         /*
  1038.           The buffer is empty;  read output from the remote FTP server.
  1039.         */
  1040.         count=read(master,buffer,sizeof(buffer));
  1041.         q=buffer;
  1042.         if (count <= 0)
  1043.           {
  1044.             if (p == line)
  1045.               return((char *) NULL);
  1046.             break;
  1047.           }
  1048.       }
  1049.     count--;
  1050.     *p=(*q++);
  1051.     if (*p == '\n')
  1052.       break;
  1053.     p++;
  1054.     if ((p-line) >= 5)
  1055.       if (!strncmp(p-5,"ftp> ",5))
  1056.         if (count == 0)
  1057.           return((char *) NULL);
  1058.   } while (p < (line+sizeof(line)));
  1059.   *p='\0';
  1060.   if (isdigit(*line))
  1061.     status=atoi(line)/100;
  1062.   return(line);
  1063. }
  1064.  
  1065. /*
  1066. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1067. %                                                                             %
  1068. %                                                                             %
  1069. %                                                                             %
  1070. %   m a i n                                                                   %
  1071. %                                                                             %
  1072. %                                                                             %
  1073. %                                                                             %
  1074. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1075. %
  1076. %
  1077. */
  1078. int main(argc,argv)
  1079. int
  1080.   argc;
  1081.  
  1082. register char
  1083.   **argv;
  1084. {
  1085. #include <pwd.h>
  1086.  
  1087.   char
  1088.     *account,
  1089.     command[2048],
  1090.     *home_directory,
  1091.     *host_info,
  1092.     *hostname,
  1093.     *ident,
  1094.     *port,
  1095.     *send_expression,
  1096.     *user;
  1097.  
  1098.   int
  1099.     binary,
  1100.     child,
  1101.     dialog,
  1102.     process_status;
  1103.  
  1104.   register char
  1105.     *p,
  1106.     *response;
  1107.  
  1108.   struct sigaction
  1109.     action;
  1110.  
  1111.   unsigned int
  1112.     prune,
  1113.     timeout,
  1114.     verbose;
  1115.  
  1116.   /*
  1117.     Initialize program variables.
  1118.   */
  1119.   account=(char *) NULL;
  1120.   client_name=argv[0];
  1121.   binary=False;
  1122.   directory_expression=(RegularExpression *) NULL;
  1123.   exclude_expression=(RegularExpression *) NULL;
  1124.   ident=(char *) NULL;
  1125.   port=(char *) NULL;
  1126.   print_expression=(RegularExpression *) NULL;
  1127.   prune=False;
  1128.   retrieve_expression=(RegularExpression *) NULL;
  1129.   send_expression=(char *) NULL;
  1130.   timeout=0;
  1131.   user=(char *) NULL;
  1132.   verbose=False;
  1133.   /*
  1134.     Parse command line arguments.
  1135.   */
  1136.   for (p=(*argv++); *argv && (**argv == '-'); argv++)
  1137.     switch (argv[0][1])
  1138.     {
  1139.       case 'a':
  1140.       {
  1141.         account=(*++argv);
  1142.         break;
  1143.       }
  1144.       case 'b':
  1145.       {
  1146.         binary=True;
  1147.         break;
  1148.       }
  1149.       case 'd':
  1150.       {
  1151.         directory_expression=CompileRegularExpression(*++argv);
  1152.         if (!directory_expression)
  1153.           exit(1);
  1154.         break;
  1155.       }
  1156.       case 'e':
  1157.       {
  1158.         exclude_expression=CompileRegularExpression(*++argv);
  1159.         if (!exclude_expression)
  1160.           exit(1);
  1161.         break;
  1162.       }
  1163.       case 'i':
  1164.       {
  1165.         ident=(*++argv);
  1166.         break;
  1167.       }
  1168.       case 'p':
  1169.       {
  1170.         if (strncmp("port",*argv+1,2) == 0)
  1171.           port=(*++argv);
  1172.         else
  1173.           if (strncmp("prune",*argv+1,3) == 0)
  1174.             prune=(**argv == '-');
  1175.           else
  1176.             {
  1177.               print_expression=CompileRegularExpression(*++argv);
  1178.               if (!print_expression)
  1179.                 exit(1);
  1180.             }
  1181.         break;
  1182.       }
  1183.       case 'r':
  1184.       {
  1185.         retrieve_expression=CompileRegularExpression(*++argv);
  1186.         if (!retrieve_expression)
  1187.           exit(1);
  1188.         break;
  1189.       }
  1190.       case 's':
  1191.       {
  1192.         send_expression=(*++argv);
  1193.         break;
  1194.       }
  1195.       case 't':
  1196.       {
  1197.         timeout=atoi(*++argv);
  1198.         break;
  1199.       }
  1200.       case 'u':
  1201.       {
  1202.         user=(*++argv);
  1203.         break;
  1204.       }
  1205.       case 'v':
  1206.       {
  1207.         verbose=True;
  1208.         break;
  1209.       }
  1210.       default:
  1211.       {
  1212.         Error("Unrecognized option",(char *) NULL);
  1213.         break;
  1214.       }
  1215.     }
  1216.   if ((argc < 2) || (*argv == (char *) NULL))
  1217.     Usage();
  1218.   hostname=argv[0];
  1219.   home_directory=argv[1];
  1220.   if ((directory_expression == (RegularExpression *) NULL) &&
  1221.       (print_expression == (RegularExpression *) NULL) &&
  1222.       (retrieve_expression == (RegularExpression *) NULL) &&
  1223.       (send_expression == (char *) NULL))
  1224.     directory_expression=CompileRegularExpression("");
  1225.   if ((ident == (char *) NULL) && (user == (char *) NULL))
  1226.     {
  1227.       static char
  1228.         name[2048];
  1229.  
  1230.       struct passwd
  1231.         *user_info;
  1232.  
  1233.       /*
  1234.         Identify user as user@host.domain.
  1235.       */
  1236.       user_info=getpwuid(geteuid());
  1237.       if (user_info == (struct passwd *) NULL)
  1238.         (void) strcpy(name,"anonymous");
  1239.       else
  1240.         (void) strcpy(name,user_info->pw_name);
  1241.       p=name+strlen(name);
  1242.       *p++='@';
  1243.       (void) gethostname(p,64);
  1244.       while (*p)
  1245.         p++;
  1246.       *p++='.';
  1247.       (void) getdomainname(p,64);
  1248.       user="anonymous";
  1249.       ident=name;
  1250.     }
  1251.   host_info=GetHostInfo(hostname);
  1252.   if (host_info == (char *) NULL)
  1253.     Error("Unknown host",hostname);
  1254.   if (home_directory == (char *) NULL)
  1255.     (void) fprintf(stdout,"%s\n",host_info);
  1256.   else
  1257.     (void) fprintf(stdout,"%s %s\n",host_info,home_directory);
  1258.   (void) GetPseudoTerminal();
  1259.   /*
  1260.     Set signal handlers.
  1261.   */
  1262.   action.sa_handler=SignalAlarm;
  1263.   (void) sigemptyset(&action.sa_mask);
  1264.   action.sa_flags=0;
  1265.   (void) sigaction(SIGALRM,&action,(struct sigaction *) NULL);
  1266.   if (timeout != 0)
  1267.     (void) alarm(timeout/10);  /* enable login timer. */
  1268.   action.sa_handler=SignalChild;
  1269.   (void) sigaction(SIGCHLD,&action,(struct sigaction *) NULL);
  1270.   /*
  1271.     Connect and logon to host.
  1272.   */
  1273.   child=fork();
  1274.   if (child < 0)
  1275.     Error("Unable to fork",(char *) NULL);
  1276.   if (child == 0)
  1277.     ExecuteFtp(hostname,port);
  1278.   while ((response=Wait()))
  1279.     if (verbose)
  1280.       (void) fprintf(stderr,"%s\n",response);
  1281.   if (user == (char *) NULL)
  1282.     user="anonymous";
  1283.   (void) sprintf(command,"user %s\n",user);
  1284.   (void) write(master,command,strlen(command));
  1285.   /*
  1286.     Logon dialog may require a password or account information.
  1287.   */
  1288.   dialog=0;
  1289.   while ((response=Wait()))
  1290.   {
  1291.     if (verbose)
  1292.       (void) fprintf(stderr,"%s\n",response);
  1293.     if (status == 3)
  1294.       {
  1295.         unsigned int
  1296.           count;
  1297.  
  1298.         switch (dialog)
  1299.         {
  1300.           case 0:
  1301.           {
  1302.             count=read(master,command,sizeof(command));
  1303.             if (ident == (char *) NULL)
  1304.               {
  1305.                 command[count]='\0';
  1306.                 ident=(char *) GetPassword(command);
  1307.               }
  1308.             (void) sprintf(command,"%s\n",ident);
  1309.             (void) write(master,command,strlen(command));
  1310.             break;
  1311.           }
  1312.           case 1:
  1313.           {
  1314.             (void) read(master,command,sizeof(command));
  1315.             if (account == (char *) NULL)
  1316.               {
  1317.                 command[count]='\0';
  1318.                 account=(char *) GetPassword(command);
  1319.               }
  1320.             (void) sprintf(command,"%s\n",account);
  1321.             (void) write(master,command,strlen(command));
  1322.             break;
  1323.           }
  1324.         }
  1325.         dialog++;
  1326.       }
  1327.     if (status == 5)
  1328.       Error(response,user);
  1329.     if (strcmp(response,"Not connected.") == 0)
  1330.       Error("unable to connect to remote host",hostname);
  1331.   }
  1332.   if (timeout != 0)
  1333.     (void) alarm(timeout);  /* enable session timer. */
  1334.   if (home_directory != (char *) NULL)
  1335.     {
  1336.       /*
  1337.         Change remote working directory.
  1338.       */
  1339.       (void) sprintf(command,"cd %s\n",home_directory);
  1340.       (void) write(master,command,strlen(command));
  1341.       while ((response=Wait()))
  1342.       {
  1343.         if (verbose)
  1344.           (void) fprintf(stderr,"%s\n",response);
  1345.         if (status == 5)
  1346.           Error("No such directory",home_directory);
  1347.       }
  1348.       (void) strcpy(command,"pwd\n");
  1349.       (void) write(master,command,strlen(command));
  1350.       while ((response=Wait()))
  1351.         if (verbose)
  1352.           (void) fprintf(stderr,"%s\n",response);
  1353.     }
  1354.   if (binary)
  1355.     {
  1356.       /*
  1357.         Set file transfer type.
  1358.       */
  1359.       (void) strcpy(command,"binary\n");
  1360.       (void) write(master,command,strlen(command));
  1361.       while ((response=Wait()))
  1362.         if (verbose)
  1363.           (void) fprintf(stderr,"%s\n",response);
  1364.       (void) strcpy(command,"type\n");
  1365.       (void) write(master,command,strlen(command));
  1366.       while ((response=Wait()))
  1367.         if (verbose)
  1368.           (void) fprintf(stderr,"%s\n",response);
  1369.     }
  1370.   if (retrieve_expression != (RegularExpression *) NULL)
  1371.     {
  1372.       /*
  1373.         Ensure retrieved files are unique.
  1374.       */
  1375.       (void) strcpy(command,"runique\n");
  1376.       (void) write(master,command,strlen(command));
  1377.       while ((response=Wait()))
  1378.         if (verbose)
  1379.           (void) fprintf(stderr,"%s\n",response);
  1380.     }
  1381.   if (send_expression == (char *) NULL)
  1382.     ProcessRequest(prune,verbose);
  1383.   else
  1384.     {
  1385.       /*
  1386.         Process send request.
  1387.       */
  1388.       (void) strcpy(command,"glob on\n");
  1389.       (void) write(master,command,strlen(command));
  1390.       while ((response=Wait()))
  1391.         if (verbose)
  1392.           (void) fprintf(stderr,"%s\n",response);
  1393.       (void) sprintf(command,"mput %s\n",send_expression);
  1394.       (void) write(master,command,strlen(command));
  1395.       while ((response=Wait()))
  1396.         if ((status == 5) || verbose)
  1397.           (void) fprintf(stderr,"%s\n",response);
  1398.     }
  1399.   (void) strcpy(command,"quit\n");
  1400.   (void) write(master,command,strlen(command));
  1401.   /*
  1402.     Wait for child to finish.
  1403.   */
  1404.   action.sa_handler=SIG_DFL;
  1405.   (void) sigemptyset(&action.sa_mask);
  1406.   action.sa_flags=0;
  1407.   (void) sigaction(SIGCHLD,&action,(struct sigaction *) NULL);
  1408.   (void) waitpid(child,&process_status,WNOHANG);
  1409.   (void) close(master);
  1410.   if (directory_expression != (RegularExpression *) NULL)
  1411.     (void) free((char *) directory_expression);
  1412.   if (exclude_expression != (RegularExpression *) NULL)
  1413.     (void) free((char *) exclude_expression);
  1414.   if (print_expression != (RegularExpression *) NULL)
  1415.     (void) free((char *) print_expression);
  1416.   if (retrieve_expression != (RegularExpression *) NULL)
  1417.     (void) free((char *) retrieve_expression);
  1418.   return(status < 0);
  1419. }
  1420.